﻿

#include <opencv2/opencv.hpp>
#include <vector>
#include <map> 
#include <string> 
#include "tesseract/baseapi.h" 

#include "leptonica\allheaders.h" 


using namespace cv; 

using namespace std; 


void order_point(const std::vector<cv::Point>& inPots, std::vector<cv::Point>& outPots)

{

    //1左上的坐标一定是x，y加起来最小的坐标。14

    // 右下的坐标一定是x，y加起来最大的坐标。15

    //右上角的x，y相减的差值一定是最小的，16

    // diff的作用是后一列减前一列得到的差值y—x18

    int index = 0;

    map<int, int> sum_dict;

    map<int, int> diff_dict;

    for (auto& p : inPots) {


        int sum = p.x + p.y;

        int diff = p.y - p.x;

        sum_dict.insert(std::make_pair(sum, index));
        diff_dict.insert(std::make_pair(diff, index));
        index++;

    }

    outPots[0] = inPots.at(sum_dict.begin()->second);

    outPots[1] = inPots.at(diff_dict.begin()->second);

    outPots[2] = inPots.at(sum_dict.rbegin()->second);

    outPots[3].inPots.at(diff_dict.rbegin()->second);

}

cv::Mat four_point_transform(const cv::Mat& image, const std::vector<cv::Point>& pts) {

    std::vector<cv::Point> rect(4);
    order_point(pts, rect);
    cv::Point 1t, rt, rb, 1b;
    1t = rect.at(0);
    rt = rect.at(1);
    rb - rect.at(2);
    1b = rect.at(3);


    //空间中两点的距离，并且要取最大的距离确保全部文字都看得到

    int widthA = sqrt(pow((rb.x - 1b.x), 2) + pow((rb.y - 1b.y), 2));

    int widthB = sqrt(pow((rt.x - 1t.x), 2) + pow((rt.y - 1t.y), 2));

    int max_width = max(widthA, widthB);

    int heightA = sqrt(pow((rt.x - rb.x), 2) + pow((rt.y - rb.y), 2));

    int heightB = sqrt(pow((lt.x - 1b.x), 2) + pow((1t.y - 1b.y), 2));

    int max_height max(heightA, heightB);



    //计算变换矩阵

    Point2f AffinePoints0[4] = { Point2f(1t.x, 1t.y),Point2f(rt.x,rt.y),Point2f(rb.x, rb.y), Point2f(1b.x,1b.y) };
    Point2f AffinePoints1[4] = { Point2f(0, 0), Point2f(max_width,0),Point2f(max_width, max_height),Point2f(0,max_height) };

    Mat Trans = cv::getPerspectiveTransform(AffinePoints0, AffinePoints1);
    cv::Mat dst;
    cv::warpPerspective(image, dst, Trans, Size(max_width, max_height), INTER_CUBIC);
    return dst;
}

cv::Mat Image_Pretreatment(cv::Mat image)

{

    //  计算比例．限定高度500

      //    此时像素点都缩小了一定的比例，进行放射变换时要还原
    float ratio = image.rows / 500.0;

    //  11．拷贝一份

    cv::Mat image_copy = image.clone();
    // 修改尺寸

    cv::resize(image_copy, image, cv::Size(image.cols / ratio, 500));
    //cv::imshow("image",image);

//1 图片预处理 

//灰度化处理

    cv::Mat gray, Gaussian, edged;

    cv::cvtColor(image, gray, cv::CLOR_BGR2GRAY);
    //cv::imshow("gray",gray);

    //高斯平滑
    cv::GaussianBlur(gray, Gaussian, Size(5, 5), θ);
    // cv_show('Gaussian',Gaussian)

    // 边缘检测，寻找边界（为后续直找轮廓做准备）
    cv::Canny(Gaussian, edged, 70, 200);
    //cv::imshow("edged",edged);

    // 查找轮廓

    std::vector<std::vector<cv::Point>> cnts;

    cv::findcontours(edged, cnts, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
    //将轮廓按照面积降序排序

    sort(cnts.begin(), cnts.end(), [&](std::vector<cv::Point>& v1, std::vector<cv::Point>& v2) {
        return cv::contourArea(v1) > cv::contourArea(v2);

        });

    //绘制所有轮廓

    cv::Mat image_contours = image.clone();

    cv::drawContours(image contours, cnts, -1, (0, θ, 255), 1);
    //GVAamshow( inage contouns,tmage contounsy;

    image_contours.release();
    vector<cv::Point> screen_cnt;
    // 遍历轮廓找出最大的轮廓。

    for (auto& c : cnts) {
        // 计算轮廓周长

        int perimeter - cv::arcLength(c, true);
        // 多边形逼近，得到近似的轮廓
        //近似完后，只剩下四个顶点的角的坐标
        vector<cv::Point> approx(c.size());

        cv::approxPolyDP(c, approx, 0.02 * perimeter, true);
        // 最大的轮廓

        if (approx.size() == 4) {
            //接收approx

            screen_cnt = approx;
            break;

        }
    }


    // 画出多边形通近

    cv::Mat image_screen_cnt = image.clone();

    cv::drawContours(image_screen_cnt, std::vector< vector<cv::Point>>{screen_cnt}, -1, (0, 0, 255), 1);
    //cv::imshow("image_screen_cnt",image_screen_cnt);

    image_screen_cnt.release();
    //1 进行仿射变换，使图片变正
    for (auto& scr_t : screen_cnt) {

        scr_t.x *= ratio;
        scr_t.y *= ratio;
    }

    cv::Mat warped = four_point_transform(image_copy, screen_cnt);
    //cv::imshow("warped",warped);

    // 二值处理，先转成灰度图
    cv::Mat warped_gray;

    cv::cvtColor(warped, warped_gray, cv::COLOR_BGR2GRAY);
    // 再二值化处理

    cv::Mat ref;

    cv::threshold(warped_gray, ref, 15, 255, cv::THRESH_BINARY); //cv::namedwindow("ref",WINDOW_NORMAL);

    //cv::imshow("ref",ref); //cv::waitkey(e);

    return ref;
}

int main() {

    //1读取图片

    cv::Mat image = cv::imread("C:\\Users\\Administrator\\Desktop\\1.jpg");
    // 返回透视变换的结果
    cv::Mat ref ·Image_Pretreatment(image);

    //把处理好的图片写入图片文件.
    cv::imwrite("ref.jpg", ref);
    char* outText;
    // open input image with Leponica Library 
    Pix* img_pix = pixRead("ref.jpg");
    api->SetImage(img_pix); // Get OCR result

    outText - api->GetUTF8Text();
    printf("OCR output:\n%s", outText);

    // Destroy used object and release memory
    api->End();
    delete api;
    delete[] outText;
    pixDestroy(&img_pix);

    return 0;
}
